using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
using System.Text;

using Routine.Utilities;

using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.Common.Helpers;
using Styx.Pathing;

using CommonBehaviors.Actions;

using Singular.Dynamics;
using Singular.Helpers;
using Singular.Managers;
using Singular.Settings;

using Action = Styx.TreeSharp.Action;
//
using Rest = Singular.Helpers.Rest;
//
using FarmerJoe.Helpers;



namespace dotty1_0
{
    public class Routine : CombatRoutine
    {
        /// <summary>
        /// The name of this CombatRoutine
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        public override string Name { get { return "Dotty1.0"; } }


        /// <summary>
        /// The <see cref="T:Styx.WoWClass"/> to be used with this routine
        /// </summary>
        /// <value>
        /// The class.
        /// </value>
        public override WoWClass Class { get { return WoWClass.Warlock; } }


        private Composite _combat, _buffs;


        public override Composite CombatBehavior { get { return _combat; } }
        public override Composite PreCombatBuffBehavior { get { return _buffs; } }
        public override Composite CombatBuffBehavior { get { return _buffs; } }

        public DateTime LastCastTime = DateTime.Now;

        public override void Initialize()
        {
            _combat = CreateCombat();
            _buffs = CreateBuffs();
        }

		private int addCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.Location.Distance(StyxWoW.Me.Location) <= 30
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }

		private bool hasAggro()
        {
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if ((StyxWoW.Me.GroupInfo.IsInParty || StyxWoW.Me.GroupInfo.IsInRaid) && u.Guid != StyxWoW.Me.Guid && !u.IsFriendly && (u.IsHostile || u.IsNeutral) && !u.IsCritter && u.CurrentTarget.Guid == StyxWoW.Me.Guid) return true;
            }
            return false;
        }

        private int RAOEaddCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.Location.Distance(StyxWoW.Me.CurrentTarget.Location) <= 10//&& u.IsWithinMeleeRange
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }

        Composite CreateBuffs()
        {
            return new PrioritySelector(
				Cast("Dark Intent", ret => !StyxWoW.Me.HasAura("Dark Intent") && !StyxWoW.Me.Mounted),
				new Decorator( ret => !StyxWoW.Me.HasAura("Grimoire of Sacrifice") && !StyxWoW.Me.Mounted,
					new PrioritySelector(
                        //new WaitContinue(2, ret=> !SpellManager.GlobalCooldown && !StyxWoW.Me.IsCasting, new ActionAlwaysSucceed()),
						Cast("Soulburn", ret => !StyxWoW.Me.HasAura("Soulburn") && !StyxWoW.Me.GotAlivePet && !StyxWoW.Me.HasAura("Grimoire of Sacrifice")),
						Cast("Summon Felhunter", ret => StyxWoW.Me.HasAura("Soulburn") && !StyxWoW.Me.GotAlivePet && !StyxWoW.Me.HasAura("Grimoire of Sacrifice")),
						Cast("Grimoire of Sacrifice", ret => StyxWoW.Me.GotAlivePet && !StyxWoW.Me.HasAura("Grimoire of Sacrifice"))
					)
				),
				new Decorator(ret =>
					!StyxWoW.Me.HasAura("Visions of Insanity"),
					new Action(abc =>
					{
						WoWItem item = StyxWoW.Me.BagItems.Find(ret => ret.Entry == 86569);
                            if (item != null) item.Use(); 
					}))
				
			);
			
        }

		
		
        Composite CreateCombat()
        {
            return new PrioritySelector(


                // Interrupt please.
                Spell.CastOnGround("Shadowfury", ret => StyxWoW.Me.CurrentTarget.Location, 
					ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast),
                Cast("Arcane Torrent", ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast && StyxWoW.Me.CurrentTarget.Distance <= 8),
                
				// Defensive CD
                new Decorator(ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CastingSpell.CastTime > 1000 && 
					StyxWoW.Me.CurrentTarget.CurrentTarget.Guid == StyxWoW.Me.Guid && (StyxWoW.Me.CurrentTarget.CastingSpell.School == WoWSpellSchool.Shadow || 
						StyxWoW.Me.CurrentTarget.CastingSpell.School == WoWSpellSchool.Holy),
                    new PrioritySelector(
						new Action(ctx => SpellManager.StopCasting()),
                        Cast("Twilight Ward")
                    )
				),
				
                Cast("Soul Shatter", ret => hasAggro()),
				Cast("Unending Resolve", ret => StyxWoW.Me.HealthPercent < 70),
				Cast("Dark Bargain", ret => StyxWoW.Me.HealthPercent < 70 && !StyxWoW.Me.HasAura("Unending Resolve")),

				new Decorator( ret => StyxWoW.Me.HealthPercent < 50,
					new PrioritySelector(
						Cast("Soulburn", ret => !StyxWoW.Me.HasAura("Soulburn")),
						Cast("Harvest Life"),
						Cast("Drain Life")
					)
				),
				//Cast("Harvest Life", ret => StyxWoW.Me.HealthPercent < 50),
				//Cast("Drain Life", ret => StyxWoW.Me.HealthPercent < 50),
				Cast("Life Tap", ret => StyxWoW.Me.ManaPercent < 15),
				Cast("Unending Breath", ret => StyxWoW.Me.IsSwimming),
				// Heal yourself
				Cast("Healthstone", ret => StyxWoW.Me.HealthPercent < 60),
				new Decorator( ret => StyxWoW.Me.HealthPercent < 45,
					new PrioritySelector(
						Cast("Soulburn", ret => !StyxWoW.Me.HasAura("Soulburn")),
						Cast("Harvest Life"),
						Cast("Drain Life")
					)
				),

				Cast("Dark Soul: Misery"),

                new Action(ret => { UseTrinkets(); return RunStatus.Failure; }),

				// AOE
				new Decorator( ret => RAOEaddCount() > 3,
					CreateAoe()),
				
				// Normal Rotation
				Cast("Curse of the Elements", ret => StyxWoW.Me.CurrentTarget.Elite && !StyxWoW.Me.CurrentTarget.HasMyAura("Curse of the Elements")),
 				Cast ("Soulburn", ret => !StyxWoW.Me.ActiveAuras.ContainsKey("Soulburn") && CurseCount < 2),
 				new Decorator(ret => CurseCount < 2 && StyxWoW.Me.ActiveAuras.ContainsKey("Soulburn"),
					new Action(context => SpellManager.Cast("Soul Swap"))
				),
				new Decorator(ret => TargetDebuffDuration("Haunt") >= 3 && StyxWoW.Me.CastingSpell != null && StyxWoW.Me.CastingSpell.Name == "Haunt",
					new Styx.TreeSharp.Action(r => SpellManager.StopCasting())),
				Cast("Haunt", ret => TargetDebuffDuration("Haunt") < 3),
               Cast("Corruption", ret => !StyxWoW.Me.CurrentTarget.HasMyAura("Corruption") || StyxWoW.Me.CurrentTarget.AuraTimeLeft("Corruption") < 5),
                Cast("Agony", ret => !StyxWoW.Me.CurrentTarget.HasMyAura("Agony") || StyxWoW.Me.CurrentTarget.AuraTimeLeft("Agony") < 5),
				new Decorator(ret => TargetDebuffDuration("Unstable Affliction") >= 5 && StyxWoW.Me.CastingSpell != null && StyxWoW.Me.CastingSpell.Name == "Unstable Affliction",
					new Styx.TreeSharp.Action(r => SpellManager.StopCasting())),
				Cast("Unstable Affliction", ret => TargetDebuffDuration("Unstable Affliction") < 5 && StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.HealthPercent > 2),
                Cast("Unstable Affliction", ret => TargetDebuffDuration("Unstable Affliction") < 5 && !StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.HealthPercent > 20),
				Spell.CastOnGround("Shadowfury", ret => StyxWoW.Me.CurrentTarget.Location),
				Cast("Drain Soul", ret => CurseCount > 2 && StyxWoW.Me.CurrentTarget.HealthPercent < 20),
				Cast("Malefic Grasp")

				/*
                    new Decorator(ret => true,
                                  new PrioritySelector(

                                      new Decorator(ret => SpellManager.HasSpell(86121) && StyxWoW.Me.IsMoving && Timers.AutoExpire("Soulburn Soul Swap", 5000),
                                           new Sequence(
                                                new DecoratorContinue(ret => !StyxWoW.Me.HasAura("Soulburn"),
                                                    new Sequence(
                                                        Spells.Buff("Soulburn", ret => StyxWoW.Me, ret => !StyxWoW.Me.HasAura("Soulburn"), false),
                                                        new Wait(2, ret => StyxWoW.Me.HasAura("Soulburn"), new ActionAlwaysSucceed())
                                                        )),

                                                new Decorator(ret => StyxWoW.Me.HasAura("Soulburn"),
                                                    new Sequence(
                                                        //new Action(context => Spells.LUACast("Soul Swap")),
                                                        //Spells.Cast("Soul Swap")
                                                        //Spells.Buff("Soul Swap",ret=> Me.HasAura("Soulburn"))
                                                        new Action(context => SpellManager.Cast("Soul Swap"))
                                                        ))
                                                )
											)
                                      )),



                    // Automatic fall through stuff
                    new Decorator(ret => true,
                                  new PrioritySelector(

                                      Spells.Cast("Unstable Affliction", ret => StyxWoW.Me.IsMoving && Timers.SpellOkToCast("Unstable Affliction", 2700)),
                                      Spells.Cast("Haunt", ret => StyxWoW.Me.IsMoving && Timers.SpellOkToCast("Haunt", 2700)),
                                      Spells.Cast("Malefic Grasp", ret => StyxWoW.Me.IsMoving)

                                      )),

                    new Decorator(ret => StyxWoW.Me.IsCasting || StyxWoW.Me.IsChanneling, new Action(context => RunStatus.Success))
				
				
				

//                Cast("Unstable Affliction", ret => (!StyxWoW.Me.CurrentTarget.HasMyAura("Unstable Affliction") || StyxWoW.Me.CurrentTarget.AuraTimeLeft("Unstable Affliction") < 6) && 
//					StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.HealthPercent > 2 && Timers.SpellOkToCast("Unstable Affliction", 400)),
//                Cast("Unstable Affliction", ret => (!StyxWoW.Me.CurrentTarget.HasMyAura("Unstable Affliction") || StyxWoW.Me.CurrentTarget.AuraTimeLeft("Unstable Affliction") < 6) && 
//					!StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.HealthPercent > 15 && Timers.SpellOkToCast("Unstable Affliction", 700)),

/*				new Decorator(ret => !StyxWoW.Me.CurrentTarget.HasMyAura("Unstable Affliction") && Timers.SpellOkToCast("Unstable Affliction", 2500),
                    new Sequence(
                        new WaitContinue(2, ret=> !SpellManager.GlobalCooldown && !StyxWoW.Me.IsCasting, new ActionAlwaysSucceed()),
                            Cast("Unstable Affliction", ret => StyxWoW.Me.CurrentTarget.AuraTimeLeft("Unstable Affliction") < 5 && StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.HealthPercent > 2),
                            Cast("Unstable Affliction", ret => StyxWoW.Me.CurrentTarget.AuraTimeLeft("Unstable Affliction") < 5 && !StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.HealthPercent > 15)
                    )
				),
*/
				//Cast("Malefic Grasp")
/*				
				Cast("Mind Spike", ret => StyxWoW.Me.HasAura("Surge of Darkness")), // && (StyxWoW.Me.IsMoving || !StyxWoW.Me.IsMoving)),
				Cast("Shadow Word: Pain", ret => !StyxWoW.Me.CurrentTarget.HasMyAura("Shadow Word: Pain") ||
					StyxWoW.Me.CurrentTarget.ActiveAuras["Shadow Word: Pain"].TimeLeft.TotalSeconds < 4),

				new Decorator(ret => TargetDebuffDuration("Vampiric Touch") >= 5 && StyxWoW.Me.CastingSpell != null && StyxWoW.Me.CastingSpell.Name == "Vampiric Touch",
					new Styx.TreeSharp.Action(r => SpellManager.StopCasting())),
				Cast("Vampiric Touch", ret => TargetDebuffDuration("Vampiric Touch") < 5),
				//	Spelltimers.Expired("Vampiric Touch", 2000)),

				Cast("Mindbender", ret => StyxWoW.Me.HasAura("Bloodlust") || 
					StyxWoW.Me.HasAura("Time Warp") || StyxWoW.Me.HasAura("Ancient Hysteria") || 
					StyxWoW.Me.CurrentTarget.IsBoss() || Unit.NearbyUnfriendlyUnits.Count(u => u.Distance <= 40) >= 3 || StyxWoW.Me.ManaPercent < 50),
				Cast("Shadowfiend", ret => StyxWoW.Me.HasAura("Bloodlust") || 
					StyxWoW.Me.HasAura("Time Warp") || StyxWoW.Me.HasAura("Ancient Hysteria") || 
					StyxWoW.Me.CurrentTarget.IsBoss() || Unit.NearbyUnfriendlyUnits.Count(u => u.Distance <= 40) >= 3 || StyxWoW.Me.ManaPercent < 75),

				
				// Filler
				Cast("Power Infusion"),
				Cast("Mind Flay")
*/				
				
            );
        }

		Composite CreateAoe()
		{
			return new PrioritySelector(
				new Decorator( ret => !StyxWoW.Me.CurrentTarget.HasMyAura("Curse of the Elements"),
					new PrioritySelector(
						Cast("Soulburn", ctx => !StyxWoW.Me.HasAura("Soulburn")),
						Cast("Curse of the Elements")
					)
				),
				new Decorator( ret => !StyxWoW.Me.CurrentTarget.HasMyAura("Seed of Corruption"),
					new PrioritySelector(
						Cast("Soulburn", ctx => !StyxWoW.Me.HasAura("Soulburn")),
						Cast("Seed of Corruption")
					)
				),
				Spell.CastOnGround("Shadowfury", ret => StyxWoW.Me.CurrentTarget.Location),
				Cast("Harvest Life"),
				Cast("Seed of Corruption", ret => !StyxWoW.Me.CurrentTarget.HasMyAura("Seed of Corruption"))
			);
		}

		

        void UseTrinkets()
        {
            var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;
            var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;


            if(firstTrinket != null && CanUseEquippedItem(firstTrinket))
                firstTrinket.Use();


            if(secondTrinket != null && CanUseEquippedItem(secondTrinket))
                secondTrinket.Use();


        }
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }

        public static int CurseCount
        {
            get
            {
                int result = 0;

                result += StyxWoW.Me.CurrentTarget.HasMyAura("Corruption") ? 1 : 0;
                result += StyxWoW.Me.CurrentTarget.HasMyAura("Agony") ? 1 : 0;
                result += StyxWoW.Me.CurrentTarget.HasMyAura("Unstable Affliction") ? 1 : 0;
                
                return result;
            }
			//return result;
        }

        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret => SpellManager.Cast(spell)));
        }

        public static double TargetDebuffDuration(String spellName)
        {
            return StyxWoW.Me.CurrentTarget.GetAuraTimeLeft(spellName, true).TotalSeconds;
        }

        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
    }
}